home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
ddj1190.arc
/
E_FLOYD.ARC
/
SPELCHEK.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1990-10-27
|
16KB
|
477 lines
{$A+,B-,D-,E-,F-,I-,L-,N-,O-,R-,S-,V+}
{$M 6144,0,655360}
Program SpelChek;
{ SPELCHEK - A spelling checker. Copyright 1990 by Edwin T. Floyd. }
Uses Dos, Crt, Dict;
Const
Alphabetic = ['a'..'z','A'..'Z']; { Alphabetic characters }
WordChar = Alphabetic+['''']; { Default WordSet }
DefaultOutput = ''; { Default output filename (''=stdout) }
BufSize = 4096; { I/O buffer size }
Type
FileEntryPtr = ^FileEntry;
FileEntry = Record
{ Input file name list entry }
NextFile : FileEntryPtr;
FileName : PathStr;
End;
Var
FileList, LastFile : FileEntryPtr; { File name list }
WordCount : LongInt; { Total number of words examined }
BadWords : LongInt; { Total number of words not found }
OldMem : LongInt; { Original value of MemAvail }
ReturnCode : Word; { Return code for Halt }
WordSet : Set Of Char; { Words are made of these }
dab, dcd, deh, din, dor, dst, duz, user : Dictionary;
TextFile : File; { Input file }
OutFile : Text; { Output file }
HighOrder : Boolean; { If true, clear high-order bits }
FullMark : Boolean; { If true, output full markup info }
UserDict : Boolean; { If true, use a user dictionary }
SuppressOutput : Boolean; { If true, do not write output file }
Aborted : Boolean; { True if operator aborted }
OutName : PathStr; { Output file name }
UserDictName : PathStr; { User dictionary name }
DictPath : PathStr; { Dictionary path }
TextBuf : Array[1..BufSize] Of Char; { I/O buffer for TextFile }
{$S+}
Function ProcessParameter(s : String) : Boolean; Forward;
Function ParseParamString(s : String) : Boolean;
{ Extract parameters from a string and process them; return True if all OK. }
Var
i, j : Word;
ParamsOk : Boolean;
Begin
ParamsOk := True;
While (s <> '') And (s[Length(s)] = ' ') Do Dec(s[0]);
While s <> '' Do Begin
i := 1;
While (i <= Length(s)) And (s[i] = ' ') Do Inc(i);
j := Succ(i);
While (j <= Length(s)) And (s[j] <> ' ') Do Inc(j);
If Not ProcessParameter(Copy(s, i, j - i)) Then ParamsOk := False;
Delete(s, 1, Pred(j));
End;
ParseParamString := ParamsOk;
End;
Function ProcessParameter(s : String) : Boolean;
{ Process command line parameter or file name; return True if OK. }
Var
ThisFile : FileEntryPtr;
IncludeFile : Text;
ParamOk : Boolean;
i, j : Word;
IoRes : Integer;
Begin
ParamOk := True;
If (s[1] = '-') Or (s[1] = '/') Then Case UpCase(s[2]) Of
'H' : If s[3] = '-' Then HighOrder := False Else HighOrder := True;
'M' : If s[3] = '-' Then FullMark := False Else FullMark := True;
'O' : Begin { Output file }
Delete(s, 1, 2);
For i := 1 To Length(s) Do s[i] := UpCase(s[i]);
If (s <> '') And ((s[1] = '-') Or (s = 'NUL')) Then Begin
SuppressOutput := True;
OutName := '-';
End Else Begin
SuppressOutput := False;
If s = '' Then OutName := s Else OutName := FExpand(s);
End;
End;
'P' : Begin { Dictionary path }
Delete(s, 1, 2);
For i := 1 To Length(s) Do s[i] := UpCase(s[i]);
If (s <> '') Then Begin
DictPath := FExpand(s);
If DictPath[Length(DictPath)] <> '\' Then DictPath := DictPath + '\';
End Else DictPath := s;
End;
'U' : Begin { User dictionary }
Delete(s, 1, 2);
For i := 1 To Length(s) Do s[i] := UpCase(s[i]);
If (s <> '') And ((s[1] = '-') Or (s = 'NUL')) Then Begin
UserDict := False;
UserDictName := '';
End Else Begin
UserDict := True;
UserDictName := FExpand(s);
End;
End;
'W' : Begin { Word character set }
Delete(s, 1, 2);
Case s[1] Of
'+' : ;
'-' : WordSet := [];
Else Begin
WriteLn('WordSet (-W) option must be followed by + or -.');
ParamOk := False;
End;
End;
Delete(s, 1, 1);
For i := 1 To Length(s) Do
WordSet := WordSet + [s[i]];
End;
Else Begin
WriteLn('Unrecognized option: ', s);
ParamOk := False;
End;
End Else If s[1] = '@' Then Begin
Delete(s, 1, 1);
For i := 1 To Length(s) Do s[i] := UpCase(s[i]);
Assign(IncludeFile, s);
Reset(IncludeFile);
IoRes := IoResult;
If IoRes = 0 Then Begin
WriteLn('Processing include file ', s);
Repeat
ReadLn(IncludeFile, s);
IoRes := IoResult;
If IoRes = 0 Then If Not ParseParamString(s) Then ParamOk := False;
Until Eof(IncludeFile) Or (IoRes <> 0);
If IoRes <> 0 Then Begin
WriteLn('Error ', IoRes, ' reading include file');
ParamOk := False;
End;
Close(IncludeFile);
IoRes := IoResult;
End Else Begin
WriteLn('Error ', IoRes, ' opening include file ', s);
ParamOk := False;
End;
End Else Begin
New(ThisFile);
If ThisFile <> Nil Then Begin
With ThisFile^ Do Begin
NextFile := Nil;
FileName := FExpand(s);
End;
If LastFile = Nil Then FileList := ThisFile
Else LastFile^.NextFile := ThisFile;
LastFile := ThisFile;
End;
End;
ProcessParameter := ParamOk;
End;
Procedure ParseParams;
{ Interpret environment and command line parameters; display Help info. }
Var
i, j : Word;
ParamsOk : Boolean;
Ch : Char;
s : String;
Begin
WriteLn('SPELCHEK v1.0 - A spelling checker. Copyright 1990 by Edwin T. Floyd.');
ParamsOk := True;
If Not ParseParamString(GetEnv('SPELCHEK')) Then Begin
WriteLn('Error found in SET SPELCHEK=.. environment string');
ParamsOk := False;
End;
For i := 1 To ParamCount Do Begin
FillChar(s[1], 255, ' ');
s := ParamStr(i);
If Not ProcessParameter(s) Then ParamsOk := False;
End;
If Not ParamsOk Then Begin
WriteLn('At least one parameter was in error. Run SPELCHEK with no parameters');
WriteLn('to see documentation.');
Halt(1);
End Else If FileList = Nil Then Begin
WriteLn;
WriteLn(' SPELCHEK filenames.. [-H] [-W[+/-]abc..] [@name] [-Oname] [-Ppath]' );
WriteLn(' [-Uname]');
WriteLn;
WriteLn('All command line parameters are separated by spaces. Input text filenames');
WriteLn('and options may be intermixed; options are distinguished by a leading hyphen:');
WriteLn;
WriteLn(' -H[-] Clear high-order bits on input file (i.e. WordStar, default off).');
WriteLn(' -M[-] Output markup information for MARKDOC program');
WriteLn(' -W-abc.. Replace the word character set with the indicated characters');
WriteLn(' (default is all alphabetic characters, upper and lower case, apostrophe).');
WriteLn(' -W+abc.. Add additional characters to the word character set.');
WriteLn(' -O[name] Name the output file (default is name omitted => stdout).');
WriteLn(' -O- Suppress output (counts are still displayed on screen).');
WriteLn(' -Ppath Drive and directory of dictionary files.');
WriteLn(' -Uname specifies a user dictionary.');
WriteLn;
WriteLn('The "@" prefixes the name of an ASCII include file which may contain');
WriteLn('filenames, options, and nested include files, in any order.');
Write('Press any key to continue...');
Ch := ReadKey;
Write(^M);
ClrEol;
WriteLn;
WriteLn('You may use the DOS "SET" command to specify default parameters. Examples:');
WriteLn;
WriteLn(' SET SPELCHEK=-Ospell.out -W-ABCDEFGHIJKLMNOPQRSTUVWXYZ');
WriteLn(' SET SPELCHEK=@defaults.spl -O -Pc:\spell');
WriteLn;
WriteLn('Command line parameters override "SET" parameters. SPELCHEK examples:');
WriteLn;
WriteLn(' SPELCHEK document.txt -W+- -Obadwords.lst');
WriteLn(' SPELCHEK @filename.lst -Pc:\spell\dict -Obadwords.txt');
WriteLn(' SPELCHEK file1.txt -H+ -M+ -Umedterm.dct -O | MARKDOC');
WriteLn;
WriteLn('SPELCHEK was written by:');
WriteLn;
WriteLn(' Edwin T. Floyd [76067,747] (CompuServe)');
WriteLn(' #9 Adams Park Court 404/576-3305 (work)');
WriteLn(' Columbus, GA 31909 404/322-0076 (home)');
Halt(0);
End Else Begin
s := '';
If HighOrder Then ch := '+' Else ch := '-';
s := s + ' -H' + ch;
If FullMark Then ch := '+' Else ch := '-';
s := s + ' -M' + ch;
WriteLn('Options: ', s, ', -O', OutName);
If DictPath <> '' Then WriteLn(' -P', DictPath);
If UserDict Then WriteLn(' -U', UserDictName);
WriteLn('Press <Esc> to stop.');
End;
End;
{$S-}
Function FileExists(FileName : PathStr) : Boolean;
{ Return TRUE if FileName can be opened ($F parameter should be off). }
Var
f : File;
Begin
Assign(f, FileName);
Reset(f);
If IoResult = 0 Then Begin
FileExists := True;
Close(f);
End Else FileExists := False;
End;
Procedure LoadDict;
{ Load dictionaries }
Var
d : DirStr;
n : NameStr;
e : ExtStr;
found : Boolean;
Begin
If Not FileExists(DictPath+'AB.DCT') Then Begin
found := False;
If DictPath <> '' Then Begin
WriteLn('Dictionary not found in directory ', DictPath);
DictPath := '';
If FileExists('AB.DCT') Then found := True
Else WriteLn('Dictionary not found in current directory');
End;
If Not found Then Begin
FSplit(ParamStr(0), d, n, e);
If d[Length(d)] <> '\' Then d := d + '\';
DictPath := d;
If Not FileExists(DictPath+'AB.DCT') Then Begin
WriteLn('Dictionary not found in program directory');
WriteLn('Unable to locate master dictionary, terminating');
Halt(1);
End;
End;
End;
WriteLn('Loading dictionary');
dab.RestoreDictionary(DictPath+'AB.DCT');
dcd.RestoreDictionary(DictPath+'CD.DCT');
deh.RestoreDictionary(DictPath+'EH.DCT');
din.RestoreDictionary(DictPath+'IN.DCT');
dor.RestoreDictionary(DictPath+'OR.DCT');
dst.RestoreDictionary(DictPath+'ST.DCT');
duz.RestoreDictionary(DictPath+'UZ.DCT');
If UserDict Then Begin
If FileExists(UserDictName) Then Begin
WriteLn('Loading user dictionary');
user.RestoreDictionary(UserDictName)
End Else Begin
WriteLn('User dictionary not found: ', UserDictName);
WriteLn('Processing continued without user dictionary');
End;
End;
End;
Function InDict(Var s : String) : Boolean;
{ Test for word in dictionary }
Var
IsIn : Boolean;
Begin
Case s[1] Of
'A'..'B' : IsIn := dab.StringInDictionary(s);
'C'..'D' : IsIn := dcd.StringInDictionary(s);
'E'..'H' : IsIn := deh.StringInDictionary(s);
'I'..'N' : IsIn := din.StringInDictionary(s);
'O'..'R' : IsIn := dor.StringInDictionary(s);
'S'..'T' : IsIn := dst.StringInDictionary(s);
'U'..'Z' : IsIn := duz.StringInDictionary(s);
Else IsIn := False;
End;
If UserDict And Not IsIn Then IsIn := user.StringInDictionary(s);
InDict := IsIn;
End;
Function ParseInputBlock(Block : LongInt; Len : Word) : Word;
{ Check words from input block against dictionaries }
Var
Words : Word;
s : String;
i, start : Word;
Begin
i := 1;
Words := 0;
While i <= Len Do Begin
s := '';
While (i <= Len) And Not (TextBuf[i] In WordSet) Do Inc(i);
start := i;
If i <= Len Then Begin
Inc(Words);
While (i <= Len) And (Length(s) < 255)
And (TextBuf[i] In WordSet) Do Begin
Inc(s[0]);
s[Ord(s[0])] := UpCase(TextBuf[i]);
Inc(i);
End;
While (s <> '') And Not (s[1] In Alphabetic) Do Begin
Delete(s, 1, 1);
Inc(start);
End;
While (s <> '') And Not (s[Length(s)] In Alphabetic) Do
Dec(s[0]);
{ Check for posessive and for some contractions }
If s = 'WON''T' Then s := ''
Else If Length(s) > 3 Then Begin
If Copy(s, Length(s)-1, 2) = '''S' Then
Delete(s, Length(s)-1, 2)
Else If Copy(s, Length(s)-1, 2) = '''M' Then
Delete(s, Length(s)-1, 2)
Else If Copy(s, Length(s)-2, 3) = 'N''T' Then
Delete(s, Length(s)-2, 3)
Else If Copy(s, Length(s)-2, 3) = '''LL' Then
Delete(s, Length(s)-2, 3)
Else If Copy(s, Length(s)-2, 3) = '''RE' Then
Delete(s, Length(s)-2, 3)
Else If Copy(s, Length(s)-2, 3) = '''VE' Then
Delete(s, Length(s)-2, 3);
End;
If (Length(s) > 1) And Not InDict(s) Then Begin
Inc(BadWords);
If Not SuppressOutput Then Begin
If FullMark Then Write(OutFile, Block + start, ' ');
WriteLn(OutFile, s);
End;
End;
End;
End;
ParseInputBlock := Words;
End;
Procedure ProcessNextFile;
{ Open and process the next input file pointed to by FileList. }
Var
ThisFile : FileEntryPtr;
FileWords, BlockOfs, OldBad : LongInt;
i, MaxLen, Len : Word;
FileResult : Integer;
Begin
ThisFile := FileList;
With ThisFile^ Do Begin
Write(FileName, ': ');
Assign(TextFile, FileName);
Reset(TextFile, 1);
FileResult := IoResult;
If FileResult = 0 Then Begin
If FullMark And Not SuppressOutput Then
WriteLn(OutFile, '0 ', FileName);
Len := 0;
FileWords := 0;
OldBad := BadWords;
BlockOfs := 0;
Repeat
BlockRead(TextFile, TextBuf[Succ(Len)], BufSize-Len, i);
FileResult := IoResult;
If FileResult = 0 Then Begin
MaxLen := Len + i;
If HighOrder Then For i := Len To MaxLen Do
TextBuf[i] := Chr(Ord(TextBuf[i]) And $7F);
Len := MaxLen;
If Not Eof(TextFile) Then Begin
While (Len > 0) And (TextBuf[Len] In WordSet) Do Dec(Len);
If (Len = 0) Then Len := MaxLen;
End;
FileWords := FileWords + ParseInputBlock(BlockOfs, Len);
BlockOfs := BlockOfs + Len;
MaxLen := MaxLen - Len;
If MaxLen > 0 Then
Move(TextBuf[Succ(Len)], TextBuf[1], MaxLen);
Len := MaxLen;
Write(^M, FileName, ': ', FileWords, ' words, ',
BadWords-OldBad, ' bad');
While KeyPressed Do If ReadKey = ^[ Then Aborted := True;
End;
Until Eof(TextFile) Or (FileResult <> 0) Or Aborted;
Close(TextFile);
WriteLn(^M, FileName, ': ', FileWords, ' words, ',
BadWords-OldBad, ' bad');
WordCount := WordCount + FileWords;
End Else WriteLn('Unable to open input file ', FileName);
If FileResult <> 0 Then Begin
WriteLn('Error ', FileResult);
Inc(ReturnCode);
End;
FileList := NextFile;
End;
Dispose(ThisFile);
End;
{$F+}
Function HandleHeapError(Size : Word) : Integer;
Begin
WriteLn('SPELCHEK ran out of memory.');
Halt(1);
End;
{$F-}
Begin
HeapError := @HandleHeapError;
FileMode := $40;
FileList := Nil;
LastFile := Nil;
HighOrder := False;
FullMark := False;
UserDict := False;
SuppressOutput := False;
Aborted := False;
OutName := DefaultOutput;
UserDictName := '';
DictPath := '';
WordSet := WordChar;
WordCount := 0;
BadWords := 0;
ReturnCode := 0;
ParseParams;
LoadDict;
If Not SuppressOutput Then Begin
Assign(OutFile, OutName);
Rewrite(OutFile);
End;
While (FileList <> Nil) And Not Aborted Do ProcessNextFile;
If Aborted Then Begin
WriteLn('File processing aborted by operator');
If Not SuppressOutput Then WriteLn(OutFile, '***ABORTED***');
Inc(ReturnCode);
End;
If Not SuppressOutput Then Close(OutFile);
WriteLn('Final Counts: ', WordCount, ' words examined, ',
BadWords, ' words not found in dictionary');
WriteLn('Done!');
Halt(ReturnCode);
End.